﻿using System;
using System.Collections.Generic;
using System.Linq;
using G = System.Drawing;
using GI = System.Drawing.Imaging;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace OpenGameKit
{
    public class TileSheet
    {
        public int[] Tiles { get; private set; }
        private string File = "";
        internal int TileWidth;
        internal int TileHeight;
        private Color Transparent;

        /// <summary>
        /// Create the tile sheet, note that there are only 30 slots open in a tile sheet.
        /// </summary>
        /// <param name="file">The image file to load from.</param>
        /// <param name="width">The width of each tile.</param>
        /// <param name="height">The height of each tile.</param>
        public TileSheet(string file, int width, int height, Color transparent)
        {
            File = file;
            TileWidth = width;
            TileHeight = height;
            Transparent = transparent;

            Tiles = new int[30];
        }

        /// <summary>
        /// Creates a tile. Can't use -1 as that is a empty tile.
        /// </summary>
        /// <param name="id">The tile id, note that the number can't be more than 30.</param>
        /// <param name="gridX">The x grid location of the tile.</param>
        /// <param name="gridY">The y grid location of the tile.</param>
        public void Define(int id, int gridX, int gridY)
        {
            try
            {
                G.Bitmap B = new G.Bitmap(File);
                B.MakeTransparent(G.Color.FromArgb(Transparent.A, Transparent.R, Transparent.G, Transparent.B));

                int Tex;
                GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);

                GL.GenTextures(1, out Tex);
                GL.BindTexture(TextureTarget.Texture2D, Tex);

                GI.BitmapData Data = B.LockBits(new G.Rectangle(gridX * TileWidth, gridY * TileHeight, 
                    TileWidth, TileHeight), GI.ImageLockMode.ReadOnly,
                    GI.PixelFormat.Format32bppPArgb);

                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Data.Width, Data.Height, 0, PixelFormat.Bgra,
                    PixelType.UnsignedByte, Data.Scan0);
                B.UnlockBits(Data);

                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);

                B.Dispose();

                Tiles[id] = Tex;
            }
            catch (Exception)
            {
                Exception e = new Exception("Failed to load image from file.");
                throw e;
            }
        }

        public void Dispose()
        {
            for (int i = 0; i < 30; i++)
            {
                GL.DeleteTextures(1, ref i);
            }

            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Call this when the tile is no longer needed.
        /// </summary>
        /// <param name="id">The id of the tile to destroy.</param>
        public void DisposeTile(int id)
        {
            GL.DeleteTextures(1, ref Tiles[id]);
        }
    }
}
